import tkinter as tk
from tkinter import ttk
from PIL import Image, ImageTk
import os
from utils import resource_path
from views import CustomMessageBox
from services import FavoriteService, PracticeService
from app_state import app_state
from configs.config import FONT_CONFIG

class PracticeView(tk.Frame):
    """逐题练习视图类，负责逐题练习界面的UI展示"""

    def __init__(self, root,
                 practice_questions=None, is_error=False, error_questions=None,
                 font=None, question_font=None, on_back=None):
        super().__init__(root)
        self.root = root
        self.favorite_service = FavoriteService()
        self.practice_service = PracticeService()
        self.practice_questions = practice_questions
        self.is_error = is_error
        self.error_questions = error_questions
        self.font = font or FONT_CONFIG['default']
        self.question_font = question_font or FONT_CONFIG['question']
        self.on_back = on_back
        self.user_answers = []
        self.exam_answers = {}
        self.is_practice = True

        # 加载保存的进度，如果没有则从0开始
        if not is_error and practice_questions:
            self.current_index = self.practice_service.get_practice_progress(app_state.current_user_id, app_state.current_category)
            # 确保索引不超出范围
            if self.current_index >= len(practice_questions):
                self.current_index = 0
        else:
            self.current_index = 0

        # 创建UI组件
        self.create_widgets()

    def create_widgets(self):
        """创建逐题练习界面的所有UI组件"""
        # 清空窗口
        for widget in self.root.winfo_children():
            widget.destroy()

        # 创建返回按钮 - 图片形式
        back_img = Image.open(resource_path(os.path.join("icon", "back.png")))
        back_img = back_img.resize((30, 30), Image.Resampling.LANCZOS)
        back_photo = ImageTk.PhotoImage(back_img)
        back_btn = tk.Label(self.root, image=back_photo, cursor="hand2")
        back_btn.image = back_photo  # 保持引用
        back_btn.bind("<Button-1>", lambda e: self.on_back())
        back_btn.pack(anchor=tk.NW, pady=10, padx=10)

        # 显示练习信息
        if self.is_error and self.error_questions:
            info_text = f"{app_state.current_category}类错题 - 共{len(self.error_questions)}题"
        elif self.practice_questions:
            info_text = f"{app_state.current_category}类题目 - 共{len(self.practice_questions)}题"
        else:
            info_text = f"{app_state.current_category}类练习"

        info_label = tk.Label(self.root, text=info_text, font=self.font)
        info_label.pack(pady=10)

        # 显示第一题
        if self.is_error and self.error_questions and len(self.error_questions) > 0:
            # 错题模式始终从0开始
            self.display_question(self.error_questions[0], is_practice=True, is_error=True,
                                error_questions=self.error_questions, current_index=0)
        elif self.practice_questions and len(self.practice_questions) > 0:
            # 使用加载的进度索引
            start_index = self.current_index
            self.display_question(self.practice_questions[start_index], is_practice=True,
                                practice_questions=self.practice_questions, current_index=start_index)
        else:
            CustomMessageBox.showinfo("提示", f"没有找到{self.current_category}类题目", parent=self.root)
            self.on_back()

    def display_question(self, question, is_practice=True, is_error=False,
                         error_questions=None, practice_questions=None, current_index=0):
        """显示单个题目"""
        # 保存当前索引
        self.current_index = current_index

        # 清空除了返回按钮外的所有控件
        for widget in self.root.winfo_children()[1:]:
            widget.destroy()

        # 创建主容器
        main_container = tk.Frame(self.root)
        main_container.pack(fill=tk.BOTH, expand=True, pady=10, padx=20)

        # 题目框架
        question_frame = tk.Frame(main_container)
        question_frame.pack(fill=tk.BOTH, expand=True)

        # 创建题干和收藏按钮同一行的框架
        q_and_favorite_frame = tk.Frame(question_frame)
        q_and_favorite_frame.pack(fill=tk.X, pady=10)

        # 左侧题干区域
        q_text_frame = tk.Frame(q_and_favorite_frame)
        q_text_frame.pack(side=tk.LEFT, fill=tk.BOTH, expand=True)

        # 右侧收藏按钮区域
        favorite_frame = tk.Frame(q_and_favorite_frame, width=60, height=60)
        favorite_frame.pack(side=tk.RIGHT, padx=10, anchor=tk.NE)
        favorite_frame.pack_propagate(False)
        favorite_frame.lift()

        # 初始状态检查
        favorite_questions = self.favorite_service.get_favorite_questions(app_state.current_user_id, app_state.current_category)
        # 调试信息：检查favorite_questions的类型和元素类型
        # print(f"favorite_questions类型: {type(favorite_questions)}")
        # if favorite_questions:
        #     print(f"favorite_questions第一个元素类型: {type(favorite_questions[0])}")
        #     print(f"元素内容: {favorite_questions[0]}")
        # 兼容实体对象和字典两种类型
        is_favorite = any(
            q.id == question.id if hasattr(q, 'id') else q.get('id') == question.id
            for q in favorite_questions
        )
        img_path = resource_path(os.path.join('icon', 'favorite_on.png')) if is_favorite else resource_path(os.path.join('icon', 'favorite_off.png'))

        # 使用PIL调整图片大小
        image = Image.open(img_path)
        image = image.resize((30, 30), Image.LANCZOS)
        favorite_img = ImageTk.PhotoImage(image)

        # 收藏按钮 - 开关样式
        def update_favorite_icon():
            nonlocal favorite_img
            # 使用favorite_service获取收藏题目
            favorite_questions = self.favorite_service.get_favorite_questions(app_state.current_user_id, app_state.current_category)
            is_favorite = any(q.id == question.id for q in favorite_questions)
            img_path = resource_path(os.path.join('icon', 'favorite_on.png')) if is_favorite else resource_path(os.path.join('icon', 'favorite_off.png'))
            # 调整新图片大小
            image = Image.open(img_path)
            image = image.resize((30, 30), Image.LANCZOS)
            favorite_img = ImageTk.PhotoImage(image)
            favorite_btn.config(image=favorite_img)
            favorite_btn.image = favorite_img  # 保持引用
            return is_favorite

        # 确保框架可见
        favorite_frame.update_idletasks()

        # 创建图片标签作为收藏按钮
        favorite_btn = tk.Label(favorite_frame, image=favorite_img, cursor="hand2")
        favorite_btn.image = favorite_img  # 保持引用
        favorite_btn.bind("<Button-1>", lambda e: toggle_favorite())
        favorite_btn.pack(pady=5)

        # 在收藏图片下方添加'收藏'文字标签
        favorite_label = tk.Label(favorite_frame, text='收藏', fg='white', bg=favorite_frame['bg'])
        favorite_label.pack(pady=(2, 0))

        # 显示题号、题型和题干
        question_number = current_index + 1
        total_questions = 0
        if is_practice and practice_questions:
            total_questions = len(practice_questions)
        elif is_error and error_questions:
            total_questions = len(error_questions)

        def toggle_favorite():
            is_favorite = update_favorite_icon()
            if is_favorite:
                self.favorite_service.remove_favorite_question(app_state.current_user_id, question.id)
            else:
                self.favorite_service.add_favorite_question(app_state.current_user_id, question.id, app_state.current_category)
            update_favorite_icon()

        type_text = "单选题" if question.type == 1 else "多选题"
        question_text = f"第{question_number}/{total_questions}题 ({type_text}): {question.Q}"
        q_label = tk.Label(q_text_frame, text=question_text, anchor=tk.CENTER,
                          font=self.question_font, wraplength=900, justify=tk.LEFT)
        q_label.pack(anchor=tk.W)

        # 显示图片(如果有)
        if hasattr(question, 'F') and question.F and question.F.startswith('data:image/png;base64,'):
            try:
                import base64
                from io import BytesIO

                # 提取base64数据
                base64_data = question.F.split(',')[1]
                # 解码base64数据
                image_data = base64.b64decode(base64_data)
                # 创建BytesIO对象
                image_buffer = BytesIO(image_data)
                # 打开图片
                image = Image.open(image_buffer)
                # 调整图片大小，保持宽高比
                max_width = 500
                max_height = 180
                width, height = image.size
                aspect_ratio = width / height
                if width > max_width:
                    width = max_width
                    height = int(width / aspect_ratio)
                if height > max_height:
                    height = max_height
                    width = int(height * aspect_ratio)
                image = image.resize((width, height), Image.LANCZOS)
                # 转换为Tkinter可用的图片
                tk_image = ImageTk.PhotoImage(image)
                # 创建标签显示图片
                img_label = tk.Label(question_frame, image=tk_image)
                img_label.image = tk_image  # 保持引用
                img_label.pack(pady=10)
            except Exception as e:
                # 如果处理失败，显示错误信息
                img_label = tk.Label(question_frame, text=f"[图片加载失败: {str(e)}]", font=self.font, fg='red')
                img_label.pack(pady=10)

        # 重置用户答案变量
        self.user_answers = []  # 用于多选题

        # 显示选项
        options_frame = tk.Frame(question_frame)
        options_frame.pack(anchor=tk.W, pady=10)

        # 选项列表
        options = [
            ('A', question.A),
            ('B', question.B),
            ('C', question.C),
            ('D', question.D)
        ]

        if question.type == 1:  # 单选题
            # 重新创建单选按钮变量
            self.user_answer = tk.StringVar(value='-1')

            # 如果有已保存的答案，加载它
            if question.id in self.exam_answers:
                saved_answer, _ = self.exam_answers[question.id]
                self.user_answer.set(saved_answer)

            for opt_key, opt_text in options:
                if opt_text:
                    # 创建Frame包含按钮和标签
                    opt_frame = ttk.Frame(options_frame, cursor="hand2")
                    opt_frame.pack(anchor=tk.W, pady=5, fill=tk.X)
                    # 为Frame添加点击事件
                    def toggle_radio(event, key=opt_key):
                        self.user_answer.set(key)
                    opt_frame.bind("<Button-1>", toggle_radio)

                    # 单选按钮
                    rb = ttk.Radiobutton(opt_frame, variable=self.user_answer, value=opt_key)
                    rb.pack(side=tk.LEFT, padx=(0, 5))

                    # 选项文本标签
                    opt_label = ttk.Label(opt_frame, text=f"{opt_key}. {opt_text}",
                                          wraplength=900, anchor=tk.W, justify=tk.LEFT, cursor="hand2")
                    opt_label.pack(side=tk.LEFT, fill=tk.X)
                    # 为标签添加点击事件
                    opt_label.bind("<Button-1>", toggle_radio)
        else:  # 多选题
            self.user_answers = []
            # 创建多选按钮变量
            self.check_vars = {}
            for opt_key, opt_text in options:
                if opt_text:
                    var = tk.BooleanVar(value=False)
                    self.check_vars[opt_key] = var

                    # 创建Frame包含按钮和标签
                    opt_frame = ttk.Frame(options_frame, cursor="hand2")
                    opt_frame.pack(anchor=tk.W, pady=5, fill=tk.X)

                    # 复选按钮
                    cb = ttk.Checkbutton(opt_frame, variable=var)
                    cb.pack(side=tk.LEFT, padx=(0, 5))

                    # 选项文本标签
                    opt_label = ttk.Label(opt_frame, text=f"{opt_key}. {opt_text}",
                                          wraplength=900, anchor=tk.W, justify=tk.LEFT, cursor="hand2")
                    opt_label.pack(side=tk.LEFT, fill=tk.X)

                    # 为标签和Frame添加点击事件处理
                    def toggle_checkbox(event, var=var):
                        var.set(not var.get())

                    opt_label.bind("<Button-1>", toggle_checkbox)
                    opt_frame.bind("<Button-1>", toggle_checkbox)

        # 底部布局 - 包含答案区域和按钮组
        btn_frame = tk.Frame(main_container)
        btn_frame.pack(fill=tk.X, side=tk.BOTTOM, pady=10)

        # 答案显示区域 - 放置在底部布局的左侧
        self.answer_frame = tk.Frame(btn_frame)
        self.answer_frame.pack(side=tk.LEFT, padx=20, pady=5)

        # 创建按钮组框架 - 放置在底部布局的右侧
        button_group_frame = tk.Frame(btn_frame)
        button_group_frame.pack(side=tk.RIGHT, padx=20, pady=5)

        # 创建按钮组框架 - 放置在底部布局的右侧
        button_group_frame = tk.Frame(btn_frame)
        button_group_frame.pack(side=tk.RIGHT, padx=20, pady=5)

        # 通用上一题/下一题处理函数
        def go_to_previous_common(questions, is_error_mode=False):
            # 检查当前题目的答案
            self.check_answer(question)
            # 如果是练习模式，保存上一题进度
            if not is_error_mode:
                self.practice_service.save_practice_progress(app_state.current_user_id, app_state.current_category, current_index - 1)
            # 延迟切换题目，以便用户有时间看到答案
            self.root.after(1000, lambda: 
                self.display_question(questions[current_index - 1], 
                                      is_practice=True, 
                                      is_error=is_error_mode, 
                                      error_questions=questions if is_error_mode else None, 
                                      practice_questions=questions if not is_error_mode else None, 
                                      current_index=current_index - 1))

        def go_to_next_common(questions, is_error_mode=False):
            # 检查当前题目的答案
            self.check_answer(question)
            # 如果是练习模式，保存下一题进度
            if not is_error_mode:
                self.practice_service.save_practice_progress(app_state.current_user_id, app_state.current_category, current_index + 1)
            # 延迟切换题目，以便用户有时间看到答案
            self.root.after(1000, lambda: 
                self.display_question(questions[current_index + 1], 
                                      is_practice=True, 
                                      is_error=is_error_mode, 
                                      error_questions=questions if is_error_mode else None, 
                                      practice_questions=questions if not is_error_mode else None, 
                                      current_index=current_index + 1))

        # 确定当前使用的题目列表
        current_questions = error_questions if is_error else practice_questions
        is_error_mode = is_error

        # 上一题按钮 - 始终显示，第一题时禁用
        prev_img_path = resource_path(os.path.join("icon", "last_disabled.png")) if current_index == 0 else resource_path(os.path.join("icon", "last.png"))
        prev_img = Image.open(prev_img_path)
        prev_img = prev_img.resize((30, 30), Image.Resampling.LANCZOS)  # 调整图片大小
        prev_photo = ImageTk.PhotoImage(prev_img)
        prev_btn = tk.Label(button_group_frame, image=prev_photo, cursor="hand2")
        prev_btn.image = prev_photo  # 保持引用
        if current_index != 0:
            prev_btn.bind("<Button-1>", lambda e: go_to_previous_common(current_questions, is_error_mode))
        prev_btn.pack(side=tk.LEFT, padx=10)

        # 查看答案按钮 - 图片形式
        check_img_path = resource_path(os.path.join("icon", "look_answer.png"))
        check_img = Image.open(check_img_path)
        check_img = check_img.resize((40, 40), Image.Resampling.LANCZOS)  # 调整图片大小
        check_photo = ImageTk.PhotoImage(check_img)
        check_btn = tk.Label(button_group_frame, image=check_photo, cursor="hand2")
        check_btn.image = check_photo  # 保持引用
        check_btn.bind("<Button-1>", lambda e: self.check_answer(question))
        check_btn.pack(side=tk.LEFT, padx=10)

        # 如果是错题模式，添加删除按钮
        if is_error and error_questions:
            # 删除错题按钮 - 图片形式
            delete_img = Image.open(resource_path(os.path.join("icon", "remove.png")))
            delete_img = delete_img.resize((30, 30), Image.Resampling.LANCZOS)  # 调整图片大小
            delete_photo = ImageTk.PhotoImage(delete_img)
            delete_btn = tk.Label(button_group_frame, image=delete_photo, cursor="hand2")
            delete_btn.image = delete_photo  # 保持引用
            delete_btn.bind("<Button-1>", lambda e: [self.favorite_service.remove_favorite_question(app_state.current_user_id, question.id),
                                                  CustomMessageBox.showinfo("提示", "已将本题移除", parent=self.root),
                                                  error_questions.pop(current_index),
                                                  len_error := len(error_questions),
                                                  self.display_question(error_questions[min(current_index, len_error-1)] if len_error > 0 else None, 
                                                                        is_practice=True, 
                                                                        is_error=True, 
                                                                        error_questions=error_questions, 
                                                                        current_index=min(current_index, len_error-1)) if len_error > 0 else self.on_back()])
            delete_btn.pack(side=tk.LEFT, padx=10)

        # 下一题按钮 - 始终显示，最后一题时禁用
        next_img_path = resource_path(os.path.join("icon", "next_disabled.png")) if current_index >= len(current_questions) - 1 else resource_path(os.path.join("icon", "next.png"))
        next_img = Image.open(next_img_path)
        next_img = next_img.resize((30, 30), Image.Resampling.LANCZOS)  # 调整图片大小
        next_photo = ImageTk.PhotoImage(next_img)
        next_btn = tk.Label(button_group_frame, image=next_photo, cursor="hand2")
        next_btn.image = next_photo  # 保持引用
        if current_index < len(current_questions) - 1:
            next_btn.bind("<Button-1>", lambda e: go_to_next_common(current_questions, is_error_mode))
        next_btn.pack(side=tk.LEFT, padx=10)

    def check_answer(self, question):
        # 清空答案显示区域
        for widget in self.answer_frame.winfo_children():
            widget.destroy()

        # 获取用户答案
        if question.type == 1:  # 单选题
            user_answer = self.user_answer.get()
            if user_answer == '-1':
                user_answer = ''
        else:  # 多选题
            user_answer = ''.join([opt_key for opt_key, var in self.check_vars.items() if var.get()])

        # 显示正确答案
        correct_answer = question.T

        # 检查答案是否正确
        is_correct = False
        if user_answer:
            is_correct = sorted(user_answer) == sorted(correct_answer)

        # 记录用户答案到exam_answers字典
        self.exam_answers[question.id] = (user_answer, is_correct)

        # 根据答案是否正确设置样式
        style = "success" if is_correct else "danger"
        answer_label = ttk.Label(self.answer_frame, text=f"正确答案: {correct_answer}", 
                                 font=self.font, style=style, wraplength=900)
        answer_label.pack(anchor=tk.W)

        # 检查答案并添加到错题本（如果错误或未作答）
        if hasattr(self, 'is_practice') and self.is_practice:
            if is_correct:
                err_msg = "回答正确！"
            else:
                # 实际调用practice_service将错题添加到错题本
                add_result = self.practice_service.add_error_question(question.id, app_state.current_category, app_state.current_user_id)
                if add_result:
                    err_msg = "回答错误，本题已添加到错题本。"
                else:
                    err_msg = "回答错误，本题已存在于错题本中。"
            
            result_label = ttk.Label(self.answer_frame, text=err_msg, 
                                            font=self.font, style=style, wraplength=900)
            result_label.pack(anchor=tk.W)